<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>

    /* 
    显式原型: 所有函数都有一个prototype属性  ==> 显式原型属性 ==> 它指向的对象是原型对象
    隐式原型: 所有实例都有一个__proto__属性 ==> 隐式原型属性  ==> 它也指向原型对象
        实例对象的隐式等于对应构造函数显示原型
        fn.__proto__ === Fn.prototype
    原型对象:
        自定义函数的默认原型对象是一个空的Object的实例  {}
        原型对象上有一个constructor属性, 指向构造函数
    构造函数
    实例对象
    */

    function Foo () {}
    const f1 = new Foo()
    const f2 = new Foo()
    const o1 = new Object()
    const o2 = {}

    // JS引擎在执行我们的代码前, 先执行内置代码: Function / Object / Date / String / Number / Boolean
    /* 
    function Function () {}
    Function.prototype.call = function () {}
    function Object () {}
    Object.prototype.toString = function () {}
    */

    /* 内部给Function的原型对象添加一个__proto__属性, 值为Object.prototype
      Function.prototype.__proto__ = Object.prototype
    */
    
    // console.log(Function.prototype.__proto__===Object.prototype)  // true
    // console.log(Function.prototype)

    // 1. 实例的隐式原型(__proto__)等于构造函数显示原型(prototype)
    console.log(f1.__proto__===Foo.prototype) // true
    console.log(o1.__proto__===Object.prototype) // true
    // 2. 所有函数都是Function的实例, 包括它自己
    console.log(Foo.__proto__===Function.prototype) // true
    console.log(Object.__proto__===Function.prototype) // true
    console.log(Function.__proto__===Function.prototype) // true
    // 3. 自定义函数的原型对象是Object的实例
    console.log(Foo.prototype.__proto__===Object.prototype) // true
    // 4. Object的原型对象的隐式原型属性是null
    console.log(Object.prototype.__proto__===null) // true
    // 5. Function的原型是一个函数, 但它的隐式原型属性指向Object的原型对象
    console.log(typeof Function.prototype) // 'function'
    console.log(Function.prototype.__proto__ === Object.prototype) // true

  </script>
</body>
</html>